#include "IndexedMesh.h"

#include <QHash>

#include "OgreSceneManager.h"

#define max(x,y) (x>y?x:y)
#define min(x,y) (x>y?y:x)

using namespace OgreLoader;

IndexedMesh::Vertex::Vertex(int _id, double _x, double _y)
    : id(_id), x(_x), y(_y)
{
}

IndexedMesh::Edge::Edge(int a, int b)
    : v1(a), v2(b)
{
}


IndexedMesh::IndexedMesh(Model::Mesh* mesh, double _scale)
    : scale(_scale)
{
    QHash<const Model::Vertex*, int> ids;
    for(int i=0; i < mesh->vertexes()->count(); i++)
    {
        ids[mesh->vertexes()->at(i)] = i;
        vertexes.append(Vertex(i, mesh->vertexes()->at(i)->x(), mesh->vertexes()->at(i)->y()));
    }
    
    foreach(Model::Edge* edge, *(mesh->edges()))
        edges.append(Edge(ids[edge->start()], ids[edge->end()]));
}

Ogre::ManualObject* IndexedMesh::get(Ogre::SceneManager* m, double height, const char* name)
{
    using namespace Ogre;
    
    ManualObject* object = m->createManualObject(name);
    object->begin(wallMaterial, RenderOperation::OT_TRIANGLE_LIST);
    
    double txsc = 0.05;
    
    double xmax, xmin, ymax, ymin;
    xmax = xmin = vertexes[0].x;
    ymax = ymin = vertexes[0].y;
    
    foreach(Vertex vertex, vertexes)
    {
        object->position(vertex.x * scale, 0, vertex.y * scale);
        object->textureCoord(txsc*(vertex.x + vertex.y), 0);
        object->position(vertex.x * scale, height, vertex.y * scale);
        object->textureCoord(txsc*(vertex.x + vertex.y), 5);
        
        if(xmax < vertex.x) xmax = vertex.x;
        if(xmin > vertex.x) xmin = vertex.x;
        if(ymax < vertex.y) ymax = vertex.y;
        if(ymin > vertex.y) ymin = vertex.y;
    }
    
    foreach(Edge edge, edges)
    {
        object->quad(2*edge.v1, 2*edge.v2, 2*edge.v2+1, 2*edge.v1+1);
    }
    
    object->end();
    
    object->begin(floorMaterial, RenderOperation::OT_TRIANGLE_LIST);
    object->position(xmin * scale, 0, ymin * scale);
    object->textureCoord(xmin, ymin);
    object->position(xmin * scale, 0, ymax * scale);
    object->textureCoord(xmin, ymax);
    object->position(xmax * scale, 0, ymax * scale);
    object->textureCoord(xmax, ymin);
    object->position(xmax * scale, 0, ymin * scale);
    object->textureCoord(xmax, ymax);
    object->quad(0, 1, 2, 3);
    object->end();
    
    object->begin(ceilMaterial, RenderOperation::OT_TRIANGLE_LIST);
    object->position(xmin * scale, height, ymin * scale);
    object->textureCoord(xmin, ymin);
    object->position(xmin * scale, height, ymax * scale);
    object->textureCoord(xmin, ymax);
    object->position(xmax * scale, height, ymax * scale);
    object->textureCoord(xmax, ymin);
    object->position(xmax * scale, height, ymin * scale);
    object->textureCoord(xmax, ymax);
    object->quad(3, 2, 1, 0);
    object->end();
    
    return object;
}

IndexedMesh::~IndexedMesh()
{

}

void IndexedMesh::setCeilMaterial(const Ogre::String& name)
{
    ceilMaterial = name;
}

void IndexedMesh::setFloorMaterial(const Ogre::String& name)
{
    floorMaterial = name;
}

void IndexedMesh::setWallMaterial(const Ogre::String& name)
{
    wallMaterial = name;
}

